let Mod = {};
const common = function (func) {
  return new Promise((resolve, reject) => {
    try {
      func(resolve);
    } catch (error) {
      console.error(error);
      reject(error);
    }
  });
};

class PCookie {
  constructor() {
    return this;
  }
  setItem(name, value) {
    var date = new Date(); //获取当前时间
    var exp = 10; //expiresDays缩写exp(有效时间)
    date.setTime(date.getTime() + exp * 24 * 3600 * 1000); //格式化为cookie识别的时间
    document.cookie =
      name + "=" + encodeURIComponent(value) + ";expires=" + date.toGMTString(); //将name设置为10天后过期,超过这个时间name这条cookie会消失
  }
  getItem(name) {
    var arr,
      reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
    if ((arr = document.cookie.match(reg))) return decodeURIComponent(arr[2]);
    else return null;
  }
  removeItem(name) {
    var exp = new Date();
    exp.setTime(exp.getTime() - 1);
    var cval = this.getItem(name);
    if (cval != null)
      document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString(); //将时间转换成GMT格式的字符串
  }
  clear() {
    var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
    if (keys) {
      for (var i = keys.length; i--; )
        document.cookie = keys[i] + "=0;expires=" + new Date(0).toUTCString();
    }
  }
  length() {
    return document.cookie.match(/[^ =;]+(?=\=)/g).length;
  }
  key(num) {
    var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
    return keys[num];
  }
}

const stores = {
  LOCALSTORAGE: window.localStorage,
  SESSIONSTORAGE: window.sessionStorage,
  COOKIE: new PCookie(),
};

const switchData = (a, b) => {
  if (a.type !== b.type) {
    let len = a.data.length
      ? typeof a.data.length === "function"
        ? a.data.length()
        : a.data.length
      : 0;
    for (let i = 0; i < len; i++) {
      let key = a.data.key(i);
      b.data.setItem(key, a.data.getItem(key));
    }
    a.data.clear();
    return b;
  } else {
    return b;
  }
};

class Store {
  constructor(store) {
    this.store = {
      type: "LOCALSTORAGE",
      data: stores["LOCALSTORAGE"],
    };
    store.type && (this.store = { type: store.type, data: stores[store.type] });
    if (store.state) {
      for (let n in store.state) {
        this.setItem(n, store.state[n]);
      }
    }
    return this;
  }
  setDriver(storeType) {
    this.store = switchData(this.store, {
      type: storeType,
      data: stores[storeType],
    });
  }
  setItem(name, value) {
    this.store.data.setItem(name, JSON.stringify(value));
  }
  getItem(name) {
    return JSON.parse(this.store.data.getItem(name));
  }
  clearItems() {
    this.store.data.clear();
  }
  removeItem(name) {
    this.store.data.removeItem(name);
  }
}

class LocalStore {
  constructor(func) {
    func && func(this);
    this.current = null;
    this.currentKeys = [];
    this.store = null;
    return this;
  }
  setItem(name, value) {
    const that = this;
    return common((next, error) => {
      that.currentKeys.indexOf(name) < 0 && that.currentKeys.push(name);
      that.store.setItem(name, value);
      next(that);
    });
  }
  getItem(name) {
    const that = this;
    return common((next, error) => {
      next(that.store.getItem(name));
    });
  }
  keys() {
    const that = this;
    return common((next, error) => {
      next(that.currentKeys);
    });
  }
  setDriver(storeType) {
    const that = this;
    return common((next, error) => {
      that.store.setDriver(storeType);
      next(that);
    });
  }
  driver() {
    const that = this;
    return common((next, error) => {
      next(that.store.store.type);
    });
  }
  clearItems() {
    const that = this;
    return common((next, error) => {
      that.store.clearItems();
      next(that);
    });
  }
  removeItem(name) {
    const that = this;
    return common((next, error) => {
      that.store.removeItem(name);
      next(that);
    });
  }
  createInstance(options) {
    const that = this;
    return common((next, error) => {
      if (options.name) {
        that.store = Mod[options.name] = new Store(options.store);
        next(that);
      } else {
        next(null);
      }
    });
  }
  instances() {
    return common((next, error) => {
      next(Mod);
    });
  }
  destroyInstance(name) {
    const that = this;
    return common((next, error) => {
      if (Mod[name]) {
        that.store.clear();
        delete Mod[name];
      }
      next(that);
    });
  }
}

export default LocalStore;
